<template>
	<div class="es-upload__wrapper" 
		:style="{
			width:boxWidth,
			background:background,
			padding:padding,
			borderRadius:boxRadius
		}"
	>
		<view v-for="(item,index) in uploadList"
			:key="index"
		    :style="{
			  width:width,
			  height:height,
			  borderRadius:borderRadius,
			  margin:gap
			}"
		   class="es-upload-item"  @tap="onPreview(index)" >
		   <!-- 缩列图 -->
			<image class="es-upload__thumb" :key="item.url" :src="item.thumb" mode="aspectFill"
				:style="{
					width:width,
					height:height,
					borderRadius:borderRadius
				}"
			></image>
			<!-- 视频播放按钮 -->
			<view class="es-upload__play" v-if="item.fileType=='video'">
				<text class="es-upload__play__icon esfont">&#xe6ca;</text>
			</view>
			<!-- 上传进度 -->
			<view class="es-upload-progress" v-if="item.status == 'loading'">
				<view class="es-upload-progress__outer">
					<view class="es-upload-progress__inner" :style="{background:progressBg,width:(item.progress||0)+'%'}"></view>
				</view>
			</view>
			<!-- 上传失败 -->
			<view class="es-upload-error" :style="{borderRadius:borderRadius}"
				v-if="item.status == 'fail'" @tap.stop="reUpload(index)">
				<view class="es-upload-error__btn"><view class="esfont icon-fail es-upload-error__icon"></view>重新上传</view>
			</view>
			<!-- 删除按钮 -->
			<view class="es-upload__close" @tap.stop="removeImg(index)">
				<text class="es-upload__close__icon esfont">&#xe6b2;</text>
			</view>
		</view>
		<view class="es-upload-btn" v-if="uploadList.length<count" 
			@tap="chooseFile" :style="{width:width,height:height,margin:gap}">
			<text class="es-upload-btn__icon esfont">&#xe6c4;</text>
			<text class="es-upload-btn__name">{{tip||btnName}}</text>
		</view>
	</div>

</template>

<script>
	export default {
		name: "es-upload",
		props: {
			//文件列表数据回显
			//thumb 图片缩略图或视频封面 
			//url 文件地址
			fileList: {
				type: Array,
				default: function() {
					return [];
				}
			},
			//服务器上传接口地址
			serverUrl:{
				type: String,
				default: ''
			},
			//请求头
			header:{
				type: Object,
				default: function(){
					return {
						//放置token等
					}
				}
			},
			//表单数据
			formData:{
				type: Object,
				default: function(){
					return {}
				}
			},
			//盒子宽度
			boxWidth:{
				type: String,
				default: '688rpx'
			},
			//盒子背景色
			background:{
				type: String,
				default: '#ffffff'
			},
			//盒子内边距
			padding:{
				type: String,
				default: '25rpx'
			},
			//盒子圆角
			boxRadius:{
				type: String,
				default: '16rpx'
			},
			//图片宽度
			width: {
				type: String,
				// #ifdef MP-WEIXIN
				default: '205rpx'
				// #endif
				// #ifndef MP-WEIXIN
				default: '202rpx'
				// #endif
			},
			//图片高度
			height: {
				type: String,
				default: '150rpx'
			},
			//图片圆角
			borderRadius:{
				type: String,
				default: '8rpx'
			},
			//图片之间的边距
			gap:{
				type: String,
				default: '5rpx'
			},
			//最多可以选择的文件个数
			count:{
				type: Number,
				default: 9
			},
			//文件类型
			mediaType:{
				type: Array,
				default: ['image', 'video']
			},
			//图片和视频选择的来源
			sourceType:{
				type: Array,
				default: ['album', 'camera']
			},
			//拍摄视频最长拍摄时间，单位秒。时间范围为 3s 至 60s 之间。不限制相册。
			maxDuration:{
				type: Number,
				default: 10
			},
			//是否压缩所选文件，基础库2.25.0前仅对 mediaType 为 image 时有效，2.25.0及以后对全量 mediaType 有效
			sizeType:{
				type: Array,
				default: ['original', 'compressed']
			},
			//仅在 sourceType 为 camera 时生效，使用前置或后置摄像头
			camera:{
				type: String,
				default: 'back'
			},
			//单个文件大小限制 MB
			size: {
				type: Number,
				default: 10
			},
			//app-图像裁剪参数，设置后 sizeType 失效
			crop:{
				type: Object,
				default: function(){
					return {};
				}
			},
			//是否压缩所选的视频源文件，默认值为 true，需要压缩。
			compressed:{
				type: Boolean,
				default: false
			},
			//上传按钮提示
			tip:{
				type: String,
				default: ''
			},
			//进度条背景色
			progressBg:{
				type: String,
				default: '#45D4A8'
			}
		},
		data() {
			return {
				loading: true,
				url: "",
				uploadList: []
			}
		},
		computed:{
			btnName(){
				let names = [];
				if(this.mediaType.includes('image')){
					names.push("图片")
				}
				if(this.mediaType.includes('video')){
					names.push("视频")
				}
				return names.join("/")
			}
		},
		watch: {
			fileList:{
				immediate:true,
				handler(vals){
					this.uploadList = vals.map(item=>{
						return  {
							fileType:item.fileType,//文件类型
							url:item.url,//文件地址
							thumb:item.thumb||item.url,//缩略图
							status:item.status||'success',//上传成功
						};
					})
				}
			},
			uploadList(vals){
				for (let i = 0; i < vals.length; i++) {
					if(vals[i].status == 'ready'){
						//开始上传
						this.$set(this.uploadList[i],"status", "loading");
						this.handleUpload(i);
					}
				}
			}
		},
		methods: {
			handleUpload(index){
				if(!this.serverUrl){
					uni.showToast({
						icon:"none",
						title:"未配置上传接口"
					})
					return;
				}
				let _this = this;
				let item = this.uploadList[index];
				const uploadTask = uni.uploadFile({
					url: this.serverUrl, //仅为示例，非真实的接口地址
					filePath:  item.tempFilePath,
					name: 'file',
					header:this.header,
					formData: this.formData,
					success: (uploadFileRes) => {
						if (uploadFileRes.statusCode == 200) {
							//返回结果 此处需要按接口实际返回进行修改
							let res = JSON.parse(uploadFileRes.data);
							//接口请求正常
							if(res.code == 200){
								_this.$set(_this.uploadList[index],"url", res.url);
								_this.$set(_this.uploadList[index],"status", "success");
								//上传成功，回调
								_this.emit();
							}
							//接口请求失败
							else{
								_this.$set(_this.uploadList[index],"status", "fail");
							}
						}else{
							_this.$set(_this.uploadList[index],"status", "fail");
						}
					},
					fail:(msg)=>{
						_this.$set(_this.uploadList[index],"status", "fail");
						uni.showToast({
							icon:"none",
							title:"fail-上传失败"
						});
					}
				});
				//监听进度条
				uploadTask.onProgressUpdate((res) => {
					_this.$set(_this.uploadList[index],"progress", res.progress);
				});
			},
			reUpload(index){
				this.$set(this.uploadList[index],"status", "loading");
				this.$set(this.uploadList[index],"progress", "0");
				this.handleUpload(index);
			},
			chooseFile() {
				// #ifdef MP-WEIXIN
				this.chooseMedia()
				// #endif
				// #ifndef MP-WEIXIN
				let itemList = [];
				if(this.mediaType.includes('image')){
					itemList.push("图片");
				}
				if(this.mediaType.includes('video')){
					itemList.push("视频");
				}
				if(itemList.length == 1){
					if(itemList[0] == '视频'){
						this.chooseVideo()
					}else{
						this.chooseImage()
					}
				}else{
					uni.showActionSheet({
						itemList:itemList
					})
				}
				
				// #endif
			},
			// #ifdef MP-WEIXIN
			chooseMedia(){
				let _this = this;
				uni.chooseMedia({
					count: this.count - this.uploadList.length,
					mediaType: this.mediaType,
					sourceType: this.sourceType,
					maxDuration: this.maxDuration,
					sizeType: this.sizeType,
					camera: this.camera,
					success(res) {
						let tempFiles = res.tempFiles;
						let uploadList = [];
						for (let i = 0; i < tempFiles.length; i++) {
							let tempFile = tempFiles[i];
							
							//过滤超出大小限制文件
							let size = tempFile.size;
							
							if (_this.size * 1024 * 1024 < size) {
								let err = `单个文件大小不能超过：${_this.size}MB`
								uni.showToast({
									icon:"none",
									title:err
								});
								continue;
							}
							let uploadItem = {
								fileType:tempFile.fileType,//文件类型
								url:"",//文件地址
								thumb:tempFile.fileType=='video'?tempFile.thumbTempFilePath:tempFile.tempFilePath,//缩列图
								tempFilePath:tempFile.tempFilePath,//临时文件地址
								status:'ready',//待上传
							}
							if(tempFile.fileType=='video'){
								Object.assign(uploadItem, { width: tempFile.width, height: tempFile.height,duration:tempFile.duration });
							}
							uploadList.push(uploadItem);
						}
						_this.uploadList = _this.uploadList.concat(uploadList);
					},
					fail:function(e){
						console.log(e)
					}
				})
			},
			// #endif
			// #ifndef MP-WEIXIN
			chooseVideo(){
				let _this = this;
				uni.chooseVideo({
					sourceType:this.sourceType,
					compressed:this.compressed,
					maxDuration:this.maxDuration,
					camera:this.camera,
					success:function(res){
						let tempFile = res.tempFile;
						let uploadList = [];
						//过滤超出大小限制文件
						let size = res.size;
						
						if (_this.size * 1024 * 1024 < size) {
							let err = `单个视频大小不能超过：${_this.size}MB`
							uni.showToast({
								icon:"none",
								title:err
							});
							return;
						}
						
						_this.uploadList.push({
							fileType:"video",//文件类型
							url:"",//文件地址
							thumb:"",//todo 视频缩列图
							tempFilePath:res.tempFilePath,//临时文件地址
							width:res.width,
							height:res.height,
							duration:res.duration,
							status:'ready',//待上传
						})
					
					},
					fail:function(e){
						console.log(e)
					}
					
				})
			},
			chooseImage(){
				let _this = this;
				uni.chooseImage({
					count: this.count - this.uploadList.length,
					sizeType: this.sizeType,
					sourceType:this.sourceType,
					crop:this.crop,
					success:function(res){
						let tempFiles = res.tempFiles;
						let uploadList = [];
						for (let i = 0; i < tempFiles.length; i++) {
							let tempFile = tempFiles[i];
							
							//过滤超出大小限制图片
							let size = tempFile.size;
							
							if (_this.size * 1024 * 1024 < size) {
								let err = `单个图片大小不能超过：${_this.size}MB`
								uni.showToast({
									icon:"none",
									title:err
								});
								continue;
							}
							uploadList.push({
								fileType:"image",//文件类型
								url:"",//文件地址
								thumb:tempFile.path,//缩列图
								tempFilePath:tempFile.path,//临时文件地址
								status:'ready',//待上传
							})
						}
						_this.uploadList = _this.uploadList.concat(uploadList);
					},
					fail:function(e){
						console.log(e)
					}
				})
			},
			// #endif
			removeImg(index) {
				this.uploadList.splice(index, 1);
				this.emit();
			},
			onPreview(index){
				let item = this.uploadList[index];
				this.$emit('click', {index,item});
				if(item.fileType == 'video'){
					uni.navigateTo({
						url:`/pages/common/video-preview?url=${item.url||item.tempFilePath}`
					})
				}else{
					uni.previewImage({
						current: item.url,
						urls: [item.url]
					})
				}
			},
			emit() {
				this.$emit('change', this.uploadList);
			}
		}
	}
</script>

<style>
	.es-upload__wrapper {
		display: flex;
		flex-direction: row;
		align-items: center;
		flex-wrap: wrap;
		box-sizing: border-box;
	}
	
	.es-upload-item {
		display: flex;
		align-items: center;
		justify-content: center;
		position: relative;
		box-sizing: border-box;
	}
	
	.es-upload__thumb{
		position: absolute;
		left: 0;
		top: 0;
	}

	.es-upload__play {
		width: 60rpx;
		height: 60rpx;
		border-radius: 60rpx;
		background-color: rgba(0, 0, 0, 0.4);
		display: flex;
		align-items: center;
		justify-content: center;
		position: relative;
		z-index: 1;
	}
	
	.es-upload__play__icon {
		font-size: 25rpx;
		color: #ffffff;
	}
	
	.es-upload-progress{
		width: calc(100% - 10rpx);
		height: 10rpx;
		position: absolute;
		left: 5rpx;
		bottom: 5rpx;
	}
	
	.es-upload-progress__outer{
		width: 100%;
		height: 100%;
		background-color: #f6f8fb;
		border-radius: 10rpx;
		position: relative;
	}
	
	.es-upload-progress__inner{
		position: absolute;
		left: 0;
		top: 0;
		height: 100%;
		border-radius: 10rpx;
		transition: width .6s ease;
	}
	
	.es-upload-error{
		width: 100%;
		height: 100%;
		position: absolute;
		left: 0;
		bottom: 0;
		display: flex;
		align-items: center;
		justify-content: center;
		color: #ffffff;
		font-size: 22rpx;
		z-index: 99;
		background-color: rgba(0, 0, 0, 0.4);
	}
	
	.es-upload-error__icon{
		font-size: 25rpx;
		color: #f6f8fb;
		margin-right: 5rpx;
	}
	
	.es-upload-error__btn{
		width: 140rpx;
		height: 40rpx;
		border-radius: 8rpx;
		background: #999999;
		display: flex;
		align-items: center;
		justify-content: center;
	}
	
	.es-upload__close {
		position: absolute;
		right: 12rpx;
		top: 10rpx;
		width: 36rpx;
		height: 36rpx;
		border-radius: 36rpx;
		background-color: rgba(0, 0, 0, 0.2);
		display: flex;
		align-items: center;
		justify-content: center;
		z-index: 99;
	}

	.es-upload__close__icon {
		font-size: 18rpx;
		color: #ffffff;
	}

	.es-upload-btn {
		border: 2rpx dashed #E1E1E1;
		border-radius: 8rpx;
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		box-sizing: border-box;
	}

	.es-upload-btn__icon {
		font-size: 52rpx;
		color: #D6D6D6;
	}

	.es-upload-btn__name {
		font-size: 24rpx;
		font-weight: 500;
		color: #B6B6B6;
		margin-top: 10rpx;
	}
</style>
